/*****************************************************************************/
/*                                                                           */
/*    Domino Operation System Driver Module                                  */
/*    FAT File System Routines (FAT12, FAT16, FAT32)                         */
/*                                                                           */
/*    Copyright (C) 2006-2012 Laszlo Arvai                                   */
/*                                                                           */
/*    ------------------------------------------------------------------   */
/*    fileFAT - Main code for FAT filesystem handling                        */
/*****************************************************************************/
#ifndef __filefileFAT_h
#define __filefileFAT_h

/*****************************************************************************/
/* Includes                                                                  */
/*****************************************************************************/
#include <krnlTypes.h>
#include <krnlDateTime.h>
#include "sysSettings.h"

/*****************************************************************************/
/* Constants                                                                 */
/*****************************************************************************/
#define fileMAX_FILENAME_LENGTH			12
#define fileMAX_FAT_FILENAME_LENGTH	11
#define fileMAX_LFN_LENGTH					256
#define fileFAT_SECTOR_LENGTH				512

// FAT type
#define fileFAT_TYPE_FAT12 1
#define fileFAT_TYPE_FAT16 2
#define fileFAT_TYPE_FAT32 3

// Open mode
#define fileFAT_OPEN_MODE_UNUSED		0x00
#define fileFAT_OPEN_MODE_CLOSED		0x01
#define fileFAT_OPEN_MODE_READONLY	0x02
#define fileFAT_OPEN_MODE_READWRITE	0x03

// attributes
#define fileFAT_ATTR_READ_ONLY	0x01
#define fileFAT_ATTR_HIDDEN			0x02
#define fileFAT_ATTR_SYSTEM			0x04
#define fileFAT_ATTR_VOLUME_ID	0x08
#define fileFAT_ATTR_DIRECTORY	0x10
#define fileFAT_ATTR_ARCHIVE		0x20
#define fileFAT_ATTR_LONG_NAME (fileFAT_ATTR_READ_ONLY | \
														fileFAT_ATTR_HIDDEN | \
														fileFAT_ATTR_SYSTEM | \
														fileFAT_ATTR_VOLUME_ID)

#define fileFAT_ATTR_LONG_NAME_MASK		(fileFAT_ATTR_READ_ONLY | \
																	fileFAT_ATTR_HIDDEN | \
																	fileFAT_ATTR_SYSTEM | \
																	fileFAT_ATTR_VOLUME_ID | \
																	fileFAT_ATTR_DIRECTORY | \
																	fileFAT_ATTR_ARCHIVE )

// buffering mode
#define fileFAT_BM_SINGLE										1	// only one buffer is used
#define fileFAT_BM_SYSTEM_AND_FILE					2 // separated buffer is used for directory/fat and file data
#define fileFAT_BM_SYSTEM_AND_PER_FILE			3 // one buffer is used for directory/fat and all files have separated buffer

// separator characters
#define fileFAT_PATH_SEPARATOR 

// if not defined then set default buffering mode
#ifndef filefileFAT_BUFFERING_MODE
#define filefileFAT_BUFFERING_MODE fileFAT_BM_SINGLE
#endif

/*****************************************************************************/
/* Macros                                                                    */
/*****************************************************************************/
#ifdef filefileFAT_MULTI_DRIVE_SUPPORT
#define fileGET_VOLUME_INFO_FROM_FILE(file)  (&g_file_volume_info[file.VolumeIndex])
#define fileSET_FILE_VOLUME_INDEX(file,index) file->VolumeIndex = index

#else
#define fileGET_VOLUME_INDEX_FROM_FILE(file)  (0)
#define fileGET_VOLUME_INDEX_FROM_DRIVE(drive) (0)
#define fileSET_FILE_VOLUME_INDEX(file,index) // do nothing when multi volume is not supported
#endif

/*****************************************************************************/
/* Types                                                                     */
/*****************************************************************************/

// Define cluster address type
#ifdef fileFAT32_SUPPORT
typedef dosDWord fatClusterAddress;	/// Cluster address type
#else
typedef dosWord fatClusterAddress;	/// Cluster address type
#endif

// Sector data buffer
struct _fatSectorBuffer
{
	dosByte Buffer[fileFAT_SECTOR_LENGTH];
	dosDWord LBA;
	#ifndef fileREAD_ONLY_FILESYSTEM
	dosBool Modified;
	#endif
};
typedef struct _fatSectorBuffer fatSectorBuffer;

// File information
struct _fatFile
{
	// file properties
	dosChar ShortName[fileMAX_FAT_FILENAME_LENGTH+1];
	dosByte Attributes;
	dosDWord Size;
	dosByte OpenMode;

	// start cluster
	fatClusterAddress StartCluster;

	// current file position
	dosDWord CurrentPos;
	fatClusterAddress CurrentCluster;
	dosWord CurrentSector;
	dosWord CurrentSectorPos;

	// directory enrty position
	fatClusterAddress DirectoryCluster;
	dosWord DirectorySector;
	dosByte DirectoryEntryIndex;

	#if filefileFAT_BUFFERING_MODE == fileFAT_BM_SYSTEM_AND_PER_FILE
	fatSectorBuffer* DataBuffer;
	#endif

	#if filefileFAT_MULTI_DRIVE_SUPPORT
	dosByte VolumeIndex;
	#endif
};
typedef struct _fatFile fatFile;

typedef struct
{
	dosDWord VolumeStartLBA;
	dosByte FATType;
	dosByte SectorsPerClaster;
	dosWord FirstFATStart;
	dosWord SecondFATStart;
	dosWord DirectoryStart;
	dosWord FirstDataSector;
	fatClusterAddress DataClasterCount;
	fatSectorBuffer SystemSectorBuffer;
	dosChar DriveLetter;
	fatFile CurrentDirectory;
} fatVolumeInfo;


/*****************************************************************************/
/* Global variables                                                          */
/*****************************************************************************/


/*****************************************************************************/
/* Function prototypes                                                       */
/*****************************************************************************/

dosBool fatMountDrive(dosByte in_drive_index);
void fatUnmountDrive(dosByte in_drive_index);

void fileSetDriveLetterByVolumeIndex(dosByte in_volume_index, dosChar in_drive_letter);

dosBool fatGetFirstDirectoryEntry( fatFile* in_find_data );
dosBool fatGetNextDirectoryEntry( fatFile* in_find_data );
void fatGetFileDateTime( fatFile* in_file, dosDateTime* out_datetime );
dosBool fatChangeDirectory( fatFile* in_file );
dosWord fatGetNumberOfEntries( fatFile* in_file );

dosBool fatOpen( fatFile* in_file, dosByte in_open_flags );
dosBool fatIsEof( fatFile* in_file );
dosWord fatRead( fatFile* in_file, dosByte* out_buffer, dosWord in_buffer_size );
void fatClose( fatFile* in_file );
void fatFlushBuffer(void);
dosBool fatIsFileExists( fatFile* in_directory, fatFile* in_file );

#ifndef fileREAD_ONLY_FILESYSTEM
dosBool fatCreateFile( fatFile* in_directory, fatFile* in_file );
dosBool fatDeleteFile( fatFile* in_file );
void fatSetFileDateTime( fatFile* in_file, dosDateTime* out_datetime );
dosWord fatWrite( fatFile* in_file, dosByte* in_buffer, dosWord in_buffer_size );
#endif

// long filename support routines
#ifdef fileLONG_FILENAME_SUPPORT
dosBool fatGetLongFilename( fatFile* in_file, dosString out_buffer, dosWord in_buffer_length );
#ifndef fileREAD_ONLY_FILESYSTEM
dosBool fatSetLongFilename( fatFile* in_file, dosString in_long_name );
#endif
#endif

#endif